"""
回收站服务模块
处理脚本和文件夹的软删除、恢复和清理功能
"""

import os
import json
import shutil
from datetime import datetime, timedelta
from typing import Optional, Dict, Any, List

from services.shared.models import db, RecycleBin, UserScript, ScriptFolder
from services.shared.logger import get_logger

logger = get_logger(__name__)
from services.shared.file_utils import get_user_script_path
from services.shared.folder_utils import get_folder_full_path


class RecycleService:
    """回收站服务类"""
    
    @staticmethod
    def soft_delete_script(script: UserScript, user_id: int, username: str) -> bool:
        """
        软删除脚本
        
        Args:
            script: 脚本对象
            user_id: 用户ID
            username: 用户名
            
        Returns:
            bool: 删除是否成功
        """
        try:
            # 获取脚本文件路径
            folder_path = None
            if script.folder_id:
                folder = ScriptFolder.query.filter_by(id=script.folder_id, user_id=user_id).first()
                if folder:
                    folder_path = get_folder_full_path(folder, user_id, username)
            
            script_path = get_user_script_path(username, script.name, folder_path)
            
            # 读取脚本内容
            script_content = ""
            if os.path.exists(script_path):
                with open(script_path, 'r', encoding='utf-8') as f:
                    script_content = f.read()
            
            # 创建回收站记录
            recycle_item = RecycleBin(
                user_id=user_id,
                item_type='script',
                original_name=script.name,
                original_path=folder_path or '',
                original_folder_id=script.folder_id,
                deleted_by=user_id,
                content_data=script_content,
                meta_data=json.dumps({
                    'script_id': script.id,
                    'description': script.description,
                    'created_at': script.created_at.isoformat() if script.created_at else None,
                    'updated_at': script.updated_at.isoformat() if script.updated_at else None,
                    'file_path': script_path
                }, ensure_ascii=False)
            )
            
            # 保存到数据库
            db.session.add(recycle_item)
            
            # 删除原始脚本记录
            db.session.delete(script)
            
            # 删除文件系统中的脚本文件
            if os.path.exists(script_path):
                os.remove(script_path)
            
            db.session.commit()
            
            logger.info(f"脚本 {script.name} 已移入回收站")
            return True
            
        except Exception as e:
            db.session.rollback()
            logger.error(f"软删除脚本失败: {str(e)}")
            return False
    
    @staticmethod
    def soft_delete_folder(folder: ScriptFolder, user_id: int, username: str, force: bool = False) -> bool:
        """
        软删除文件夹
        
        Args:
            folder: 文件夹对象
            user_id: 用户ID
            username: 用户名
            force: 是否强制删除（包括子内容）
            
        Returns:
            bool: 删除是否成功
        """
        try:
            # 检查文件夹是否为空
            if not force and (folder.subfolders or folder.scripts.count() > 0):
                logger.warning(f"文件夹 {folder.name} 不为空，无法删除")
                return False
            
            # 获取文件夹路径
            folder_path = get_folder_full_path(folder, user_id, username)
            
            # 收集文件夹内容信息
            folder_contents = {
                'scripts': [],
                'subfolders': []
            }
            
            # 如果是强制删除，先处理子内容
            if force:
                # 处理脚本
                for script in folder.scripts:
                    script_content = ""
                    script_file_path = get_user_script_path(username, script.name, folder_path)
                    if os.path.exists(script_file_path):
                        with open(script_file_path, 'r', encoding='utf-8') as f:
                            script_content = f.read()
                    
                    folder_contents['scripts'].append({
                        'id': script.id,
                        'name': script.name,
                        'description': script.description,
                        'content': script_content,
                        'created_at': script.created_at.isoformat() if script.created_at else None,
                        'updated_at': script.updated_at.isoformat() if script.updated_at else None
                    })
                    
                    db.session.delete(script)
                
                # 递归处理子文件夹
                def collect_subfolder_info(subfolder):
                    subfolder_info = {
                        'id': subfolder.id,
                        'name': subfolder.name,
                        'parent_id': subfolder.parent_id,
                        'scripts': [],
                        'subfolders': []
                    }
                    
                    # 收集子文件夹中的脚本
                    for script in subfolder.scripts:
                        script_content = ""
                        subfolder_path = get_folder_full_path(subfolder, user_id, username)
                        script_file_path = get_user_script_path(username, script.name, subfolder_path)
                        if os.path.exists(script_file_path):
                            with open(script_file_path, 'r', encoding='utf-8') as f:
                                script_content = f.read()
                        
                        subfolder_info['scripts'].append({
                            'id': script.id,
                            'name': script.name,
                            'description': script.description,
                            'content': script_content,
                            'created_at': script.created_at.isoformat() if script.created_at else None,
                            'updated_at': script.updated_at.isoformat() if script.updated_at else None
                        })
                        db.session.delete(script)
                    
                    # 递归处理子文件夹
                    for sub_subfolder in subfolder.subfolders:
                        subfolder_info['subfolders'].append(collect_subfolder_info(sub_subfolder))
                        db.session.delete(sub_subfolder)
                    
                    return subfolder_info
                
                for subfolder in folder.subfolders:
                    folder_contents['subfolders'].append(collect_subfolder_info(subfolder))
                    db.session.delete(subfolder)
            
            # 创建回收站记录
            recycle_item = RecycleBin(
                user_id=user_id,
                item_type='folder',
                original_name=folder.name,
                original_path=get_folder_full_path(folder.parent, user_id, username) if folder.parent else '',
                original_folder_id=folder.parent_id,
                deleted_by=user_id,
                content_data=json.dumps(folder_contents, ensure_ascii=False),
                meta_data=json.dumps({
                    'folder_id': folder.id,
                    'parent_id': folder.parent_id,
                    'created_at': folder.created_at.isoformat() if folder.created_at else None,
                    'force_deleted': force,
                    'folder_path': folder_path
                }, ensure_ascii=False)
            )
            
            # 保存到数据库
            db.session.add(recycle_item)
            
            # 删除原始文件夹记录
            db.session.delete(folder)
            
            # 删除文件系统中的文件夹
            if os.path.exists(folder_path):
                if force:
                    shutil.rmtree(folder_path)
                else:
                    os.rmdir(folder_path)
            
            db.session.commit()
            
            logger.info(f"文件夹 {folder.name} 已移入回收站")
            return True
            
        except Exception as e:
            db.session.rollback()
            logger.error(f"软删除文件夹失败: {str(e)}")
            return False
    
    @staticmethod
    def restore_script(recycle_id: int, user_id: int, username: str) -> tuple[bool, str]:
        """
        恢复脚本
        
        Args:
            recycle_id: 回收站记录ID
            user_id: 用户ID
            username: 用户名
            
        Returns:
            tuple[bool, str]: (恢复是否成功, 失败原因或成功消息)
        """
        try:
            recycle_item = RecycleBin.query.filter_by(
                id=recycle_id, 
                user_id=user_id, 
                item_type='script'
            ).first()
            
            if not recycle_item:
                logger.warning(f"回收站记录不存在: {recycle_id}")
                return False, "回收站记录不存在"
            
            # 检查原始文件夹是否还存在
            folder_id = recycle_item.original_folder_id
            folder_warning = ""
            if folder_id:
                folder = ScriptFolder.query.filter_by(id=folder_id, user_id=user_id).first()
                if not folder:
                    # 原始文件夹不存在，恢复到根目录
                    folder_id = None
                    folder_warning = "（原始文件夹不存在，已恢复到根目录）"
            
            # 检查脚本名称是否冲突
            existing_script = UserScript.query.filter_by(
                name=recycle_item.original_name,
                user_id=user_id,
                folder_id=folder_id
            ).first()
            
            if existing_script:
                logger.warning(f"脚本名称冲突: {recycle_item.original_name}")
                return False, f"脚本名称 '{recycle_item.original_name}' 已存在，无法恢复"
            
            # 解析元数据
            meta_data = json.loads(recycle_item.meta_data) if recycle_item.meta_data else {}
            
            # 创建新的脚本记录
            script = UserScript(
                name=recycle_item.original_name,
                description=meta_data.get('description', ''),
                user_id=user_id,
                folder_id=folder_id
            )
            
            db.session.add(script)
            db.session.flush()  # 获取脚本ID
            
            # 恢复脚本文件
            folder_path = None
            if folder_id:
                folder = ScriptFolder.query.get(folder_id)
                if folder:
                    folder_path = get_folder_full_path(folder, user_id, username)
            
            script_path = get_user_script_path(username, script.name, folder_path)
            
            # 确保目录存在
            os.makedirs(os.path.dirname(script_path), exist_ok=True)
            
            # 写入脚本内容
            with open(script_path, 'w', encoding='utf-8') as f:
                f.write(recycle_item.content_data)
            
            # 删除回收站记录
            db.session.delete(recycle_item)
            db.session.commit()
            
            success_message = f"脚本 '{script.name}' 恢复成功{folder_warning}"
            logger.info(success_message)
            return True, success_message
            
        except Exception as e:
            db.session.rollback()
            error_msg = f"恢复脚本失败: {str(e)}"
            logger.error(error_msg)
            return False, error_msg
    
    @staticmethod
    def restore_folder(recycle_id: int, user_id: int, username: str) -> tuple[bool, str]:
        """
        恢复文件夹
        
        Args:
            recycle_id: 回收站记录ID
            user_id: 用户ID
            username: 用户名
            
        Returns:
            tuple[bool, str]: (恢复是否成功, 失败原因或成功消息)
        """
        try:
            recycle_item = RecycleBin.query.filter_by(
                id=recycle_id, 
                user_id=user_id, 
                item_type='folder'
            ).first()
            
            if not recycle_item:
                logger.warning(f"回收站记录不存在: {recycle_id}")
                return False, "回收站记录不存在"
            
            # 检查原始父文件夹是否还存在
            parent_id = recycle_item.original_folder_id
            folder_warning = ""
            if parent_id:
                parent_folder = ScriptFolder.query.filter_by(id=parent_id, user_id=user_id).first()
                if not parent_folder:
                    # 原始父文件夹不存在，恢复到根目录
                    parent_id = None
                    folder_warning = "（原始父文件夹不存在，已恢复到根目录）"
            
            # 检查文件夹名称是否冲突
            existing_folder = ScriptFolder.query.filter_by(
                name=recycle_item.original_name,
                user_id=user_id,
                parent_id=parent_id
            ).first()
            
            if existing_folder:
                logger.warning(f"文件夹名称冲突: {recycle_item.original_name}")
                return False, f"文件夹名称 '{recycle_item.original_name}' 已存在，无法恢复"
            
            # 解析文件夹内容
            folder_contents = json.loads(recycle_item.content_data)
            
            # 创建主文件夹
            folder = ScriptFolder(
                name=recycle_item.original_name,
                user_id=user_id,
                parent_id=parent_id
            )
            
            db.session.add(folder)
            db.session.flush()  # 获取文件夹ID
            
            # 创建文件系统目录
            folder_path = get_folder_full_path(folder, user_id, username)
            os.makedirs(folder_path, exist_ok=True)
            
            # 恢复脚本
            for script_info in folder_contents.get('scripts', []):
                script = UserScript(
                    name=script_info['name'],
                    description=script_info.get('description', ''),
                    user_id=user_id,
                    folder_id=folder.id
                )
                db.session.add(script)
                
                # 恢复脚本文件
                script_path = get_user_script_path(username, script.name, folder_path)
                with open(script_path, 'w', encoding='utf-8') as f:
                    f.write(script_info['content'])
            
            # 递归恢复子文件夹
            def restore_subfolder(subfolder_info, parent_folder_id, parent_path):
                subfolder = ScriptFolder(
                    name=subfolder_info['name'],
                    user_id=user_id,
                    parent_id=parent_folder_id
                )
                db.session.add(subfolder)
                db.session.flush()
                
                # 创建子文件夹目录
                subfolder_path = os.path.join(parent_path, subfolder.name)
                os.makedirs(subfolder_path, exist_ok=True)
                
                # 恢复子文件夹中的脚本
                for script_info in subfolder_info.get('scripts', []):
                    script = UserScript(
                        name=script_info['name'],
                        description=script_info.get('description', ''),
                        user_id=user_id,
                        folder_id=subfolder.id
                    )
                    db.session.add(script)
                    
                    # 恢复脚本文件
                    script_path = get_user_script_path(username, script.name, subfolder_path)
                    with open(script_path, 'w', encoding='utf-8') as f:
                        f.write(script_info['content'])
                
                # 递归恢复子文件夹
                for sub_subfolder_info in subfolder_info.get('subfolders', []):
                    restore_subfolder(sub_subfolder_info, subfolder.id, subfolder_path)
            
            for subfolder_info in folder_contents.get('subfolders', []):
                restore_subfolder(subfolder_info, folder.id, folder_path)
            
            # 删除回收站记录
            db.session.delete(recycle_item)
            db.session.commit()
            
            success_message = f"文件夹 '{folder.name}' 恢复成功{folder_warning}"
            logger.info(success_message)
            return True, success_message
            
        except Exception as e:
            db.session.rollback()
            error_msg = f"恢复文件夹失败: {str(e)}"
            logger.error(error_msg)
            return False, error_msg
    
    @staticmethod
    def get_recycle_items(user_id: int, page: int = 1, per_page: int = 20, item_type: str = None) -> Dict[str, Any]:
        """
        获取用户的回收站项目
        
        Args:
            user_id: 用户ID
            page: 页码
            per_page: 每页数量
            item_type: 项目类型过滤 ('script' 或 'folder')
            
        Returns:
            Dict: 包含分页信息和回收站项目列表
        """
        try:
            query = RecycleBin.query.filter_by(user_id=user_id)
            
            # 按类型过滤
            if item_type:
                query = query.filter_by(item_type=item_type)
            
            # 按删除时间倒序排列
            query = query.order_by(RecycleBin.deleted_at.desc())
            
            # 分页
            pagination = query.paginate(page=page, per_page=per_page, error_out=False)
            items = pagination.items
            
            result = []
            for item in items:
                result.append({
                    'id': item.id,
                    'type': item.item_type,
                    'name': item.original_name,
                    'path': item.original_path,
                    'deleted_at': item.deleted_at.isoformat(),
                    'days_remaining': item.days_remaining,
                    'is_expired': item.is_expired,
                    'size': len(item.content_data) if item.content_data else 0
                })
            
            return {
                'items': result,
                'pagination': {
                    'page': pagination.page,
                    'per_page': pagination.per_page,
                    'total': pagination.total,
                    'pages': pagination.pages,
                    'has_prev': pagination.has_prev,
                    'has_next': pagination.has_next
                }
            }
            
        except Exception as e:
            logger.error(f"获取回收站项目失败: {str(e)}")
            return {
                'items': [],
                'pagination': {
                    'page': 1,
                    'per_page': per_page,
                    'total': 0,
                    'pages': 0,
                    'has_prev': False,
                    'has_next': False
                }
            }
    
    @staticmethod
    def permanently_delete(recycle_id: int, user_id: int) -> bool:
        """
        永久删除回收站项目
        
        Args:
            recycle_id: 回收站记录ID
            user_id: 用户ID
            
        Returns:
            bool: 删除是否成功
        """
        try:
            recycle_item = RecycleBin.query.filter_by(id=recycle_id, user_id=user_id).first()
            
            if not recycle_item:
                logger.warning(f"回收站记录不存在: {recycle_id}")
                return False
            
            db.session.delete(recycle_item)
            db.session.commit()
            
            logger.info(f"回收站项目 {recycle_item.original_name} 已永久删除")
            return True
            
        except Exception as e:
            db.session.rollback()
            logger.error(f"永久删除失败: {str(e)}")
            return False
    
    @staticmethod
    def clean_expired_items() -> int:
        """
        清理过期的回收站项目
        
        Returns:
            int: 清理的项目数量
        """
        try:
            expired_items = RecycleBin.query.filter(
                RecycleBin.deleted_at < datetime.utcnow() - timedelta(days=30)
            ).all()
            
            count = len(expired_items)
            
            for item in expired_items:
                db.session.delete(item)
            
            db.session.commit()
            
            logger.info(f"已清理 {count} 个过期的回收站项目")
            return count
            
        except Exception as e:
            db.session.rollback()
            logger.error(f"清理过期项目失败: {str(e)}")
            return 0